package com.net.xpay.common.service.impl;

import com.net.xpay.common.domain.partner.Partner;
import com.net.xpay.common.domain.partner.PartnerAccount;
import com.net.xpay.common.domain.partner.PartnerCode;
import com.net.xpay.common.enums.partner.PartnerLevel;
import com.net.xpay.common.enums.partner.PartnerSettlePeriod;
import com.net.xpay.common.enums.user.CommissionMode;
import com.net.xpay.common.enums.user.SecurityStatus;
import com.net.xpay.common.enums.user.ServicePayMode;
import com.net.xpay.common.enums.user.UserTag;
import com.net.xpay.common.model.PartnerRegisterModel;
import com.net.xpay.core.constant.CoreConstant;
import com.net.xpay.core.constant.PoseidonErrorCode;
import com.net.xpay.core.utils.UuidUtil;
import com.net.common.exception.BusinessException;
import com.net.xpay.common.manager.partner.PartnerAccountManager;
import com.net.xpay.common.manager.partner.PartnerCodeManager;
import com.net.xpay.common.manager.partner.PartnerManager;
import com.net.xpay.common.service.PartnerService;
import lombok.extern.slf4j.Slf4j;
import org.mindrot.jbcrypt.BCrypt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;


/**
 * @author net on 30/08/2020.
 */
@Service
@Slf4j
public class PartnerServiceImpl implements PartnerService {

    @Autowired
    private PartnerManager partnerManager;

    @Autowired
    private PartnerAccountManager partnerAccountManager;

    @Autowired
    private PartnerCodeManager partnerCodeManager;


    @Override
    @Transactional(transactionManager = "xpayCommonTransactionManager", rollbackFor = Exception.class)
    public Partner registerInternal(PartnerRegisterModel registerModel) {
        if (registerModel.getLevel() == null) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "合伙人级别不能为空");
        }
        if (registerModel.getLevel() == PartnerLevel.LEVEL_2 && registerModel.getFatherPartnerId() == null) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "请选择上级合伙人");
        }
        if (registerModel.getCommissionMode() == null) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "请选择分佣模式");
        }

        if (registerModel.getFatherPartnerId() != null) {
            Partner fatherPartner = partnerManager.getById(registerModel.getFatherPartnerId());
            if (fatherPartner.getLevel() != PartnerLevel.LEVEL_1) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "上级合伙人必须是一级合伙人");
            }
        }


        Partner partner = createPartner(registerModel);
        partnerManager.save(partner);
        PartnerAccount account = PartnerAccount.getInstance(partner);
        account.setMoneyLeft(0L);
        partnerAccountManager.save(account);

        //生成默认的合伙人推广码
        genPartnerCode(registerModel, partner);

        return partner;
    }

    private void genPartnerCode(PartnerRegisterModel registerModel, Partner partner) {
        //现在只支持一级渠道 渠道下面的走销售关系
        if (partner.getLevel() == PartnerLevel.LEVEL_1) {
            //一级合伙人
            genLevel1PartnerCode(registerModel, partner);
        } else {
            //二级合伙人
            genLevel2PartnerCode(registerModel, partner);
        }
    }

    private void genLevel2PartnerCode(PartnerRegisterModel registerModel, Partner partner) {
        //上级渠道的配置
        PartnerCode fatherPartnerCode = partnerCodeManager.listByPartnerId(partner.getFatherPartnerId()).get(0);
        if (fatherPartnerCode.getCommissionMode() == CommissionMode.STAT_MODE) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "内部员工下不能被选为上级合伙人");
        }

        PartnerCode partnerCodeForPlatform = PartnerCode.getInstance();
        partnerCodeForPlatform.setPartnerId(partner.getId());
        partnerCodeForPlatform.setFatherPartnerId(partner.getFatherPartnerId());
        partnerCodeForPlatform.setPma(UuidUtil.uuid());
        partnerCodeForPlatform.setUserTag(UserTag.PLATFORM);
        partnerCodeForPlatform.setMode(ServicePayMode.FIXED_RATIO);
        partnerCodeForPlatform.setCommissionMode(registerModel.getCommissionMode() != null ? registerModel.getCommissionMode() : CommissionMode.COST_MODE);
        partnerCodeForPlatform.setServiceUnitPrice(0L);
        partnerCodeForPlatform.setServiceRatio(CoreConstant.DEFAULT_PLATFORM_SERVICE_UNIT_RATIO);
        partnerCodeForPlatform.setCostServiceRatio(CoreConstant.DEFAULT_PARTNER_COST_SERVICE_UNIT_RATIO);
        partnerCodeForPlatform.setSafePayBankCostServiceRatio(CoreConstant.DEFAULT_PARTNER_SAFE_PAY_BANK_COST_SERVICE_UNIT_RATIO);
        partnerCodeForPlatform.setBenefitRatio(new BigDecimal("0"));
        //默认继承上级渠道的百分比
        partnerCodeForPlatform.setFatherBenefitRatio(fatherPartnerCode.getBenefitRatio());
        partnerCodeForPlatform.setBenefit(0L);
        partnerCodeForPlatform.setFatherBenefit(0L);
        partnerCodeForPlatform.setStatus(1);
        partnerCodeForPlatform.setFatherCommissionMode(CommissionMode.FIXED_MODE);
        partnerCodeForPlatform.setFatherServiceRatio(new BigDecimal("0"));
        partnerCodeForPlatform.setFatherBankServiceRatio(new BigDecimal("0"));
        partnerCodeForPlatform.setBankServiceRatio(CoreConstant.DEFAULT_PLATFORM_SERVICE_UNIT_RATIO);
        partnerCodeManager.save(partnerCodeForPlatform);
    }

    private void genLevel1PartnerCode(PartnerRegisterModel registerModel, Partner partner) {
        PartnerCode partnerCodeForPlatform = PartnerCode.getInstance();
        partnerCodeForPlatform.setPartnerId(partner.getId());
        partnerCodeForPlatform.setPma(UuidUtil.uuid());
        partnerCodeForPlatform.setUserTag(UserTag.PLATFORM);
        partnerCodeForPlatform.setMode(ServicePayMode.FIXED_RATIO);
        partnerCodeForPlatform.setCommissionMode(registerModel.getCommissionMode() != null ? registerModel.getCommissionMode() : CommissionMode.COST_MODE);
        partnerCodeForPlatform.setServiceUnitPrice(0L);
        partnerCodeForPlatform.setServiceRatio(CoreConstant.DEFAULT_PLATFORM_SERVICE_UNIT_RATIO);
        partnerCodeForPlatform.setCostServiceRatio(CoreConstant.DEFAULT_PARTNER_COST_SERVICE_UNIT_RATIO);
        partnerCodeForPlatform.setSafePayBankCostServiceRatio(CoreConstant.DEFAULT_PARTNER_SAFE_PAY_BANK_COST_SERVICE_UNIT_RATIO);
        partnerCodeForPlatform.setBenefitRatio(new BigDecimal("0"));
        partnerCodeForPlatform.setFatherBenefitRatio(new BigDecimal("0"));
        partnerCodeForPlatform.setBenefit(0L);
        partnerCodeForPlatform.setFatherBenefit(0L);
        partnerCodeForPlatform.setStatus(1);
        partnerCodeForPlatform.setFatherCommissionMode(CommissionMode.FIXED_MODE);
        partnerCodeForPlatform.setFatherServiceRatio(new BigDecimal("0"));
        partnerCodeForPlatform.setFatherBankServiceRatio(new BigDecimal("0"));
        partnerCodeForPlatform.setBankServiceRatio(CoreConstant.DEFAULT_PLATFORM_SERVICE_UNIT_RATIO);
        partnerCodeManager.save(partnerCodeForPlatform);
    }


    private Partner createPartner(PartnerRegisterModel registerModel) {
        Partner partner = new Partner();
        partner.setMobile(registerModel.getMobile());
        partner.setLevel(registerModel.getLevel());
        partner.setSettlePeriod(PartnerSettlePeriod.MONTH);
        partner.setFatherPartnerId(registerModel.getFatherPartnerId());
        partner.setName(registerModel.getName());
        partner.setRemark(registerModel.getRemark());
        partner.setAlipayName(registerModel.getAlipayName());
        partner.setAlipayAccount(registerModel.getAlipayAccount());
        partner.setAutoWithdraw(false);
        partner.setRegisterTime(LocalDateTime.now());
        partner.setRegisterIp(registerModel.getIp());
        partner.setLastLoginTime(LocalDateTime.now());
        partner.setLastLoginClient(registerModel.getClientFrom());
        partner.setLastLoginIp(registerModel.getIp());
        partner.setLoginCount(0L);
        partner.setSecurityStatus(SecurityStatus.NORMAL);
        partner.setErrorCount(0);
        //需要特殊处理的字段
        setPartnerPassword(partner, registerModel.getPassword());

        return partner;
    }

    private void setPartnerPassword(Partner partner, String password) {
        //使用BCrypt加密不需要保存salt,hash值包含了salt的信息
        String crypt = BCrypt.hashpw(password, BCrypt.gensalt());
        partner.setPassword(crypt);
    }
}
